<template>
  <div ref='dataBox'>
    <el-card style='background-color: rgba(149,151,154,0.6);'>
      <div slot='header' style='display: flex;justify-content: space-between;'>
        <h3>站点数据总览</h3>
        <div>
          <el-switch active-color='rgb(24, 20, 50)' v-model='dark' @change='renderAll' />
          深色模式
        </div>
      </div>
      <el-row :gutter='10'>
        <el-col :span='6'>
          <el-card class='fx-box-card'>
            <div style='width: 100%;' ref='userAnalysis' />
          </el-card>
        </el-col>
        <el-col :span='18'>
          <el-card class='fx-box-card'>
            <div style='width: 100%;' ref='userData' />
          </el-card>
        </el-col>
      </el-row>
      <el-row :gutter='10'>
        <el-col :span='6'>
          <el-card class='fx-box-card'>
            <div style='width: 100%;' ref='blogAnalysis' />
          </el-card>
        </el-col>
        <el-col :span='18'>
          <el-card class='fx-box-card'>
            <div style='width: 100%;' ref='blogData' />
          </el-card>
        </el-col>
      </el-row>
      <el-row :gutter='10'>
        <el-col :span='24'>
          <el-card class='fx-map-card'>
            <div slot='header'>
              <h3>访客地理位置分布</h3>
            </div>
            <div class='map' style='position: relative;width: 100%;' ref='userPositionMap' />
          </el-card>
        </el-col>
      </el-row>
      <el-row :gutter='10'>
        <el-col :span='24'>
          <el-card class='box-card'>
            <div slot='header' class='clearfix'>
              <h3>访客 IP 信息</h3>
            </div>
            <div>
              <el-table
                :data='ips'
                style='width: 100%;margin-bottom: 20px;'
              >
                <el-table-column label='访客 IP' align='center' prop='ip'/>
                <el-table-column label='所属省份' align='center' prop='provience'/>
                <el-table-column label='所在城市' align='center' prop='city'/>
                <el-table-column label='访问时间' align='center' prop='visitTime'>
                  <template slot-scope='scope'>
                    <el-tag type='info' size='small'>{{ scope.row.visitTime | timeFormat }}</el-tag>
                  </template>
                </el-table-column>
              </el-table>
            </div>
            <el-pagination
              :hide-on-single-page='true'
              layout='total, prev, pager, next'
              :total='visitorIpTotal'
              :page-size='ipParams.limit'
              @current-change='changePage'
            />
          </el-card>
        </el-col>
      </el-row>
    </el-card>
  </div>
</template>

<script>
import 'echarts/extension/bmap/bmap'
import Sys_AdminService from '@/service/admin/Sys_AdminService'
import Filters from '@/tools/Filters'

export default {
  name: 'DataAnalysis',
  data() {
    return {
      boxWidth: 0,
      dark: true,
      theme: '',
      params: {},
      users: [],
      blogs: [],
      userTotal: 0,
      blogTotal: 0,
      userAnalysisOpt: {
        title: {
          text: '用户数据分析',
          subtext: '当前用户总数：',
          left: 'center'
        },
        color: ['rgb(230, 162, 60)', 'rgb(63, 158, 255)', 'rgb(103, 194, 58)'],
        tooltip: {
          trigger: 'item'
        },
        legend: {
          orient: 'horizontal',
          bottom: 'bottom'
        },
        series: [
          {
            name: '用户角色',
            type: 'pie',
            radius: '50%',
            data: [],
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            }
          }
        ]
      },
      userAnalysisChart: null,
      userDataOpt: {
        title: {
          text: '用户注册趋势'
        },
        tooltip: {
          position: function(pt) {
            return [pt[0], 130]
          },
          trigger: 'axis'
        },
        dataZoom: [
          {
            id: 'zoomX',
            type: 'inside',
            start: 0,
            end: 100
          },
          {
            id: 'zoomY',
            type: 'inside',
            start: 0,
            end: 100
          }
        ],
        xAxis: {
          type: 'category',
          name: '时间',
          boundaryGap: false,
          data: []
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          name: '注册人数',
          type: 'line',
          data: [],
          smooth: true,
          symbol: 'circle',
          sampling: 'lttb',
          itemStyle: {
            color: '#F56C6C'
          },
          areaStyle: {
            color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
              {
                offset: 0,
                color: 'rgba(255, 158, 68,0.8)'
              },
              {
                offset: 0.5,
                color: 'rgba(255, 70, 131, 0.6)'
              },
              {
                offset: 1,
                color: 'rgba(38,178,190,0.5)'
              }
            ])
          }
        }]
      },
      userDataChart: null,
      blogAnalysisOpt: {
        title: {
          text: '博文数据分析',
          subtext: '当前文章总数：',
          left: 'center'
        },
        color: ['rgb(65,137,229)', '#F56C6C'],
        tooltip: {
          trigger: 'item'
        },
        legend: {
          orient: 'horizontal',
          bottom: 'bottom'
        },
        series: [
          {
            name: '审核状态',
            type: 'pie',
            radius: '50%',
            data: [],
            emphasis: {
              itemStyle: {
                shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
              }
            }
          }
        ]
      },
      blogAnalysisChart: null,
      blogDataOpt: {
        title: {
          text: '博文发布趋势'
        },
        tooltip: {
          position: function(pt) {
            return [pt[0], 130]
          },
          trigger: 'axis'
        },
        dataZoom: [
          {
            id: 'zoomX',
            type: 'inside',
            start: 0,
            end: 100
          },
          {
            id: 'zoomY',
            type: 'inside',
            start: 0,
            end: 100
          }
        ],
        xAxis: {
          type: 'category',
          name: '时间',
          boundaryGap: false,
          data: []
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          name: '发布数量',
          type: 'line',
          data: [],
          smooth: true,
          symbol: 'circle',
          sampling: 'lttb',
          itemStyle: {
            color: '#F56C6C'
          },
          areaStyle: {
            color: new this.$echarts.graphic.LinearGradient(0, 0, 0, 1, [
              {
                offset: 0,
                color: 'rgba(255, 158, 68,0.8)'
              },
              {
                offset: 0.5,
                color: 'rgba(255, 70, 131, 0.6)'
              },
              {
                offset: 1,
                color: 'rgba(38,178,190,0.5)'
              }
            ])
          }
        }]
      },
      blogDataChart: null,
      userPositionMapOpt: {
        bmap: {
          center: [120.13066322374, 30.240018034923],
          zoom: 5,
          roam: true,
        },
        series: [
          {
            type: 'effectScatter',
            coordinateSystem: 'bmap',
            data: [[120.13066322374,30.240018034923]]
          }
        ]
      },
      userPositionMapChart: null,
      bmapStyleId: '2bf7880300dcc0e2ead24b40ac718855',
      visitorIpTotal: 0,
      ips: [],
      ipParams: {
        limit: 10,
        skip: 0
      }
    }
  },
  created() {
    this.initData()
  },
  mounted() {
    this.renderAll()
    this.$events.$on('resize', () => {
      setTimeout(() => {
        this.resizeAll()
      }, 240)
    })
    window.addEventListener('resize', () => {
      this.resizeAll()
    })
  },
  beforeDestroy() {
    this.$events.$off('resize')
  },
  filters: {
    timeFormat: Filters.timeFormat
  },
  watch: {
    userTotal() {
      this.renderAll()
    },
    blogTotal() {
      this.renderAll()
    },
    visitorIpTotal(){
      this.renderUserPositionMapChart()
    }
  },
  methods: {
    initData() {
      this.initUserData()
      this.initBlogData()
      this.initVisitorIps()
    },
    async initUserData() {
      const res = await Sys_AdminService.getUsers(this.params)
      if (res.data.status !== 200) return this.userData = []
      this.users = res.data.data.users
      this.userTotal = res.data.data.total
    },
    async initBlogData() {
      const res = await Sys_AdminService.getBlogs(this.params)
      if (res.data.status !== 200) return this.blogData = []
      this.blogs = res.data.data.blogData
      this.blogTotal = res.data.data.total
    },
    async initVisitorIps(){
      const res = await Sys_AdminService.getVisitorIps(this.ipParams)
      if (res.data.status !== 200) return this.ips = []
      this.ips = res.data.data.ips
      this.visitorIpTotal = res.data.data.total
    },
    renderAll() {
      this.$nextTick(() => {
        this.theme = this.dark ? 'dark' : 'light'
        this.bmapStyleId = this.dark ? 'd983a703d1127b83dc3427513a63aa67' : '2bf7880300dcc0e2ead24b40ac718855'
        const cards = document.querySelectorAll('.fx-box-card')
        cards.forEach(card => {
          if (this.dark) {
            card.classList.add('box-card-dark')
          } else {
            card.classList.remove('box-card-dark')
          }
        })
        const map = document.querySelector('.fx-map-card')
        if (this.dark) {
          map.classList.add('fx-map-dark')
        } else {
          map.classList.remove('fx-map-dark')
        }

        this.renderUserAnalysisChart()
        this.renderUserDataChart()
        this.renderBlogAnalysisChart()
        this.renderBlogDataChart()
        this.renderUserPositionMapChart()
      })
    },
    resizeAll() {
      const height = this.$refs.userAnalysis?.clientWidth + 'px'
      const rate = 16 / 9
      this.$refs.userAnalysis.style.height = height
      this.$refs.userData.style.height = height
      this.$refs.blogAnalysis.style.height = height
      this.$refs.blogData.style.height = height
      this.$refs.userPositionMap.style.height = this.$refs.userPositionMap.clientWidth / rate + 'px'
      this.userAnalysisChart.resize()
      this.userDataChart.resize()
      this.blogAnalysisChart.resize()
      this.blogDataChart.resize()
      this.userPositionMapChart.resize()
    },
    renderUserAnalysisChart() {
      this.$refs.userAnalysis.style.height = this.$refs.userAnalysis.clientWidth + 'px'
      if (this.userAnalysisChart) this.userAnalysisChart.dispose()
      this.userAnalysisChart = this.$echarts.init(this.$refs.userAnalysis, this.theme, {
        renderer: 'svg'
      })
      this.userAnalysisOpt.title.subtext = '当前用户总数：' + this.userTotal

      const roles = {
        '超级管理员': 0,
        '管理员': 0,
        '普通用户': 0
      }
      this.users.forEach(user => {
        if (user.superAdmin) return roles['超级管理员']++
        if (user.isAdmin) return roles['管理员']++
        roles['普通用户']++
      })
      const data = []
      for (const [name, value] of Object.entries(roles)) {
        data.push({ name, value })
      }

      this.userAnalysisOpt.series[0].data = data
      this.userAnalysisChart.setOption(this.userAnalysisOpt)
    },
    renderUserDataChart() {
      this.$refs.userData.style.height = this.$refs.userAnalysis.clientHeight + 'px'
      if (this.userDataChart) this.userDataChart.dispose()
      this.userDataChart = this.$echarts.init(this.$refs.userData, this.theme, {
        renderer: 'svg'
      })
      const times = []
      for (const user of this.users) {
        times.push(new Date(user.createTime).toLocaleDateString())
      }
      const timeData = times.reduce((obj, curr) => {
        if (obj[curr]) obj[curr]++
        else obj[curr] = 1
        return obj
      }, {})
      const data = []
      this.userDataOpt.xAxis.data = Object.keys(timeData).reverse()
      for (const [time, num] of Object.entries(timeData)) {
        data.push([time, num])
      }
      this.userDataOpt.series[0].data = data
      this.userDataChart.setOption(this.userDataOpt)
    },
    renderBlogAnalysisChart() {
      this.$refs.blogAnalysis.style.height = this.$refs.blogAnalysis.clientWidth + 'px'
      if (this.blogAnalysisChart) this.blogAnalysisChart.dispose()
      this.blogAnalysisChart = this.$echarts.init(this.$refs.blogAnalysis, this.theme, {
        renderer: 'svg'
      })
      this.blogAnalysisOpt.title.subtext = '当前博文总数：' + this.blogTotal

      const approved = {
        '已审核': 0,
        '未审核': 0
      }
      this.blogs.forEach(blog => {
        if (blog.approved) return approved['已审核']++
        approved['未审核']++
      })
      const data = []
      for (const [name, value] of Object.entries(approved)) {
        data.push({ name, value })
      }

      this.blogAnalysisOpt.series[0].data = data
      this.blogAnalysisChart.setOption(this.blogAnalysisOpt)
    },
    renderBlogDataChart() {
      this.$refs.blogData.style.height = this.$refs.blogAnalysis.clientHeight + 'px'
      if (this.blogDataChart) this.blogDataChart.dispose()
      this.blogDataChart = this.$echarts.init(this.$refs.blogData, this.theme, {
        renderer: 'svg'
      })
      const times = []
      for (const blog of this.blogs) {
        times.push(new Date(blog.lastModified).toLocaleDateString())
      }
      const timeData = times.reduce((obj, curr) => {
        if (obj[curr]) obj[curr]++
        else obj[curr] = 1
        return obj
      }, {})
      const data = []
      this.blogDataOpt.xAxis.data = Object.keys(timeData).reverse()
      for (const [time, num] of Object.entries(timeData)) {
        data.push([time, num])
      }
      this.blogDataOpt.series[0].data = data
      this.blogDataChart.setOption(this.blogDataOpt)
    },
    renderUserPositionMapChart() {
      const rate = 9 / 16
      this.$refs.userPositionMap.style.height = this.$refs.userPositionMap.clientWidth * rate + 'px'
      if (this.userPositionMapChart) this.userPositionMapChart.dispose()
      this.userPositionMapChart = this.$echarts.init(this.$refs.userPositionMap, 'light', {
        renderer: 'svg'
      })
      if(this.ips.length){
        const ipLocations = []
        this.ips.forEach(ip => {
          ipLocations.push(ip.location)
        })
        this.userPositionMapOpt.series[0].data = ipLocations
      }
      this.userPositionMapChart.setOption(this.userPositionMapOpt)
      // 获取百度地图实例
      let bmap = this.userPositionMapChart.getModel().getComponent('bmap').getBMap()
      bmap.setMapStyleV2({
        styleId: this.bmapStyleId
      })
    },
    changePage(page) {
      this.ipParams.skip = (page - 1) * this.ipParams.limit
      this.initVisitorIps().then(()=>{
        this.renderUserPositionMapChart()
      })
    }
  }
}
</script>

<style scoped>

h3 {
  margin: 0;
  padding: 0;
}

>>> .el-card {
  transition: none;
}

>>> .el-row {
  margin-bottom: 20px;
}

.fx-box-card {
  width: 100%;
}

.box-card-dark {
  background-color: rgb(16, 12, 42);
  border-color: rgb(16, 12, 42);
}

.fx-map-card{
  width: 100%;
}

.fx-map-dark{
  color: white;
  background-color: rgba(36, 47, 62);
  border-color: rgb(16, 12, 42);
}

.map {
  cursor: pointer;
}

>>> .el-table thead {
  color: rgba(0, 0, 0, 0.7);
}

>>> .el-pager li:hover,
>>> .el-pagination button:hover {
  color: rgba(250, 84, 28, 0.8);
}

>>> .el-pager li.active {
  color: rgba(250, 84, 28, 0.8);
}

</style>
